/*
 * buf_ConstString.c
 *
 *  Created on: 2012/04/01
 *      Author: guanxiaoying
 */
#include "../../parser/coredef.h"


#define BufType  PSZ
#define Buffer stConstStringManager.memoryBlocks
#define Buflen stConstStringManager.maxRecordNum
#define  bufLenPerBlk  (stConstStringManager.astMaxNum_Block)

/* get the object */
static TABLEMANAGER stConstStringManager = {
//		U4                  usIdx;
		0,
//		PSZ				    con_pszName;    constant
		__FILE__,
//		U2					con_usSize;		constant
		1,
//		U2					block_num;	　　　　　　　Reset clear  際　要
		0,
//		S4					astMaxNum_Block;     １回設定のみ
		0,
//		S4					astTabNum_LastPage; 　　　　Reset clear  際　要
		0,
//		S4					astMaxNum_LastPage;     Reset clear  際　要
		0,
//		U4					ulMaxByte;	　　　　　　　　　　クリアしない
		0,
//		U4					con_minPageSize;　　　　　　　　　　constant
		0
};
static VOID resetBufListener( U4  procid, U2 index )
{
	if( procid == stConstStringManager.u4Idx )
	{
		if( index > 0 && index < MAX_VOLUMN_OF_TABLE )
		{
			Buffer[ index-1] = NULL;
		}
	}
}
static BufType core_getBuf( AST index )
{
	BufType temp = (BufType)Check_Com( &stConstStringManager, resetBufListener, index );
	if( temp != NULL ){
		return &temp[index%bufLenPerBlk];
	}
	return NULL;
}


static BOOL AllocBuffer( AST astReqArg )
{
	return AllocBuffer_Com( &stConstStringManager, astReqArg, resetBufListener );
}
static BOOL EmptyBuffer( VOID )
{
	return AllocBuffer( - Buflen );
}
//		BOOL (*clear)( VOID );
static BOOL ClearBuffer( VOID )
{
	return Clear_Com( &stConstStringManager );
}
static BOOL ResetBuffer( VOID )
{
	return Reset_Com( &stConstStringManager );
}
#define ALIGNMENT  sizeof(S4)
/*  get method */
static CHAR * getLabel( AST index )
{
	BufType pTbl = core_getBuf( index );
	if( pTbl == NULL )
	{
		return "";
	}
	return pTbl+ALIGNMENT;
}
/*  get method */
static S4 getLength( AST index )
{
	BufType pTbl = core_getBuf( index );
	if( pTbl == NULL )
	{
		return 0;
	}
	return *(S4*)pTbl;
}
/*  get method */
static VOID setLength( AST index, S4 len )
{
	BufType pTbl = core_getBuf( index );
	if( pTbl == NULL )
	{
		*(S4*)pTbl = len;
	}
}
/* set method */
static AST  setLabel( PSZ str, U4 len )
{
	S4 starter ;
	S4 size;
	S4 cnt;
	PSZ buffer;
	AST astHeaderNo;
	if( len > 0 && len < MemGetBlockSize( )-ALIGNMENT)
	{
		size = ALIGNMENT; /* header */
		size += (len/ALIGNMENT + 1 )*ALIGNMENT;  /* buffer */
		if( AllocBuffer( size ) ) {
			starter = Buflen - size + 1;
			astHeaderNo = starter/stConstStringManager.astMaxNum_Block;
			buffer =  (PSZ)Buffer[astHeaderNo]+starter%stConstStringManager.astMaxNum_Block;
			*((S4*)buffer) = len;
			buffer += ALIGNMENT;
			cnt = 0;
			while( cnt < len ){
				*buffer = *str;
				buffer++;
				str++;
				cnt++;
			}
		}
		else
		{
			return 0;
		}
	}
	else
	{
		if ( 0 == AllocBuffer( ALIGNMENT ) )
		{
			return 0;
		}
		starter = Buflen - ALIGNMENT + 1;
		astHeaderNo = starter/stConstStringManager.astMaxNum_Block;
		buffer =  (PSZ)Buffer[astHeaderNo]+starter%stConstStringManager.astMaxNum_Block;
		*((S4*)buffer) = 0;
	}
	return starter;
}
/* set method */
static AST  appendLabel( AST index, PSZ str, U4 len )
{
	S4 lenBuf_New;
	S4 lenBuf_Old;
	S4 cnt;
	S4 size;
	AST astHeaderNo;
	PSZ buffer;
	PSZ buffer_Old;
	AST starter;

	lenBuf_Old = getLength(index);
	if( lenBuf_Old == 0 )
	{
		return setLabel(str,len);
	}
	if( len == 0 || str == NULL )
	{
		return index;
	}
	lenBuf_New = ((lenBuf_Old+len)/ALIGNMENT + 1 )*ALIGNMENT;
	if( lenBuf_New == ((lenBuf_Old/ALIGNMENT + 1 )*ALIGNMENT)){
		setLength( index, lenBuf_Old+len );
	}else if( index + lenBuf_Old + ALIGNMENT*2 >= Buflen ) {/* ALIGNMENT*2 header and buffer alignment */
		/** Buf_Old is the last one */
		if( index%stConstStringManager.astMaxNum_Block + ALIGNMENT + lenBuf_New < stConstStringManager.astMaxNum_Block )
		{
			if( AllocBuffer( lenBuf_New - ((lenBuf_Old)/ALIGNMENT + 1 )*ALIGNMENT ) ) {
				astHeaderNo = index/stConstStringManager.astMaxNum_Block;
				buffer = (PSZ)Buffer[astHeaderNo]+index%stConstStringManager.astMaxNum_Block;
				buffer += ALIGNMENT + lenBuf_Old;
				cnt = 0;
				while( cnt < len ){
					*buffer = *str;
					buffer++;
					str++;
					cnt++;
				}
				setLength( index, lenBuf_Old+len );
			}
			else
			{
				index = 0;
			}
			return index;
		}
	}
	size = ALIGNMENT;
	size += lenBuf_New;
	if( lenBuf_New > 0 && lenBuf_New < MemGetBlockSize( ))
	{
		if( AllocBuffer( size ) ) {
			starter = Buflen - size + 1;
			astHeaderNo = starter/stConstStringManager.astMaxNum_Block;
			buffer = (PSZ)Buffer[astHeaderNo]+starter%stConstStringManager.astMaxNum_Block;
			buffer += ALIGNMENT;
			buffer_Old = (PSZ)Buffer[(index+ALIGNMENT)/stConstStringManager.astMaxNum_Block]+((index+ALIGNMENT)%stConstStringManager.astMaxNum_Block);
			index = starter;
			cnt = 0;
			while( cnt < lenBuf_Old ){
				*buffer=*buffer_Old;
				buffer++;
				buffer_Old++;
				cnt++;
			}
			cnt = 0;
			while( cnt < len ){
				*buffer=*str;
				buffer++;
				str++;
				cnt++;
			}
			setLength( index, lenBuf_Old+len );
		}
		else
		{
			index = 0;
		}
	}
	else{
		index = 0;
	}
	return index;
}
const ACCESS_CCCONSTSTRING stCcConstStringAccess = {
		EmptyBuffer,
//		BOOL (*clear)( VOID );
		ClearBuffer,
//		BOOL (*reset)( VOID );
		ResetBuffer,
//		CHAR * (*getStr)( AST index );
		getLabel,
//		AST (*addStr)( PSZ str );
		setLabel,
//		AST (*appendStr)( AST index, PSZ str );
		appendLabel,
		getLength
};
